﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Acms.DatabaseTest.Helpers;
using System.Data.SqlClient;
using System.Data;

namespace Acms.DatabaseTest
{
    [TestClass]
    public class PostTests
    {
        [TestMethod]
        public void GetAllTest()
        {
            using (var conn = TestConnection.Begin())
            {
                var parentGuid = Guid.Empty;
                conn.Site_Add(1, "Site", "Root", true, true, false);
                conn.Template_Add(1, 1, "Name", "notes", 1, false, false);
                Enumerable.Range(1, 10).ToList().ForEach(i =>
                {
                    var postGuid = Guid.NewGuid();
                    conn.Post_Add(i, 1, postGuid, parentGuid, "Name " + i, "Display Name " + i, i, 1, null, "Summary " + i, DateTime.Now, null, null, "Notes" + i, true, false, false, false, "Title Summary " + i, "MetaKeywords " + i);
                    conn.PostPosition_Add(Guid.NewGuid(), i, null, null, null, null);
                });

                var results = conn.ExecuteProc("acms.Post_GetAll", new ParamCollection().AddInputParam("siteid", SqlDbType.Int, 1).AddInputParam("SiteVersion", SqlDbType.DateTime, null));

                Assert.AreEqual(10, results.Count);
            }
        }

        [TestMethod]
        public void GetByIdTest()
        {
            using (var conn = TestConnection.Begin())
            {
                conn.Site_Add(1, "site", "www.site.com", false, false, false);
                conn.Template_Add(1, 1, "template", null, 1, false, false);

                string parentPath = null;
                string parentSequence = "000";
                var postGuids = Enumerable.Range(1, 10).Select(x => Guid.NewGuid()).ToArray();
                var postPositionGuids = Enumerable.Range(1, 10).Select(x => Guid.NewGuid()).ToArray();
                var createdDated = Enumerable.Range(1, 10).Select(x => DateTime.Now.AddHours(x * -1)).ToArray();
                for (int i = 1; i <= 10; i++)
                {
                    string postName = i == 1 ? "~" : "post" + i;
                    conn.Post_Add(i,1, postGuids[i - 1], i > 1 ? postGuids[i - 2] : Guid.Empty, postName, "Post " + i, 0, 1, null, null, DateTime.Now, null, null, null, false, false, false, false, null, null);
                    conn.PostPosition_Add(postPositionGuids[i-1], i, null, parentPath, 0, parentSequence);
                    parentPath += postName + "/";
                    parentSequence += "_000";
                }

                var results = conn.ExecuteProc("acms.Post_GetById", 
                    new ParamCollection()
                        .AddInputParam("id", SqlDbType.Int, 5)
                        .AddInputParam("siteid", SqlDbType.Int, 1)
                        .AddInputParam("siteversion", SqlDbType.DateTime, null)
                    );

                var actualPost = conn.Post_Get(5);
                var actualSite = conn.Site_Get(1);
                var actualTemplate = conn.Template_Get(1);
                var actualPostPosition = conn.PostPosition_Get(postPositionGuids[4]);

                Assert.AreEqual(1, results.Count);
                Assert.AreEqual(actualPost["Id"], results.First()["Id"]);
                Assert.AreEqual(actualPost["SiteId"], results.First()["SiteId"]);
                Assert.AreEqual(actualPost["PostGuid"], results.First()["PostGuid"]);
                Assert.AreEqual(actualSite["Name"], results.First()["SiteName"]);
                Assert.AreEqual(actualPost["ParentGuid"], results.First()["ParentGuid"]);
                Assert.AreEqual(actualPost["Name"], results.First()["Name"]);
                Assert.AreEqual(actualPost["DisplayName"], results.First()["DisplayName"]);
                Assert.AreEqual(actualPost["ThumbnailId"], results.First()["ThumbnailId"]);
                Assert.AreEqual(actualPost["TemplateId"], results.First()["TemplateId"]);
                Assert.AreEqual(actualTemplate["Name"], results.First()["TemplateName"]);
                Assert.AreEqual(actualTemplate["NodeType"], results.First()["NodeType"]);
                Assert.AreEqual(actualPost["Summary"], results.First()["Summary"]);
                Assert.AreEqual(actualPost["Sequence"], results.First()["Sequence"]);
                Assert.AreEqual(actualPost["CreatedDateTime"], results.First()["CreatedDateTime"]);
                Assert.AreEqual(actualPost["PublishFrom"], results.First()["PublishFrom"]);
                Assert.AreEqual(actualPost["PublishTo"], results.First()["PublishTo"]);
                Assert.AreEqual(actualPost["RequiresPublishing"], results.First()["RequiresPublishing"]);
                Assert.AreEqual(actualPost["ReadyToPublish"], results.First()["ReadyToPublish"]);
                Assert.AreEqual(actualPost["Notes"], results.First()["Notes"]);
                Assert.AreEqual(actualPost["DeveloperLocked"], results.First()["DeveloperLocked"]);
                Assert.IsTrue(((byte[])actualPost["VersionId"]).SequenceEqual((byte[])results.First()["VersionId"]));
                Assert.AreEqual(actualPost["TitleSummary"], results.First()["TitleSummary"]);
                Assert.AreEqual(actualPost["MetaKeywords"], results.First()["MetaKeywords"]);
                Assert.AreEqual(actualPostPosition["ParentPath"], results.First()["ParentPath"]);
                Assert.AreEqual(actualPostPosition["PublishDate"], results.First()["SiteVersion"]);
            }
        }

        [TestMethod]
        public void GetByNameTest()
        {
            using (var conn = TestConnection.Begin())
            {
                Enumerable.Range(1, 10).ToList().ForEach(i =>
                    conn.Site_Add(i, "Name " + i, "www.test" + i + ".com", true, true, false)
                    );
                var results = conn.ExecuteProc("acms.Site_GetByName", new ParamCollection().AddInputParam("Name", SqlDbType.VarChar, "Name 3"));
                Assert.AreEqual(1, results.Count);
                Assert.AreEqual(3, results.First()["Id"]);
                Assert.AreEqual("Name 3", results.First()["Name"]);
            }
        }

        [TestMethod]
        public void GetByRootUrlTest()
        {
            using (var conn = TestConnection.Begin())
            {
                Enumerable.Range(1, 10).ToList().ForEach(i =>
                    conn.Site_Add(i, "Name " + i, "www.test" + i + ".com", true, true, false)
                    );
                var results = conn.ExecuteProc("acms.Site_GetByRootUrl", new ParamCollection().AddInputParam("RootUrl", SqlDbType.VarChar, "www.test4.com"));
                Assert.AreEqual(1, results.Count);
                Assert.AreEqual(4, results.First()["Id"]);
            }
        }

        [TestMethod]
        public void GetByRootUrlUsingMappingTest()
        {
            using (var conn = TestConnection.Begin())
            {
                Enumerable.Range(1, 10).ToList().ForEach(i =>
                    conn.Site_Add(i, "Name " + i, "www.test" + i + ".com", true, true, false)
                    );
                Enumerable.Range(1, 20).ToList().ForEach(i =>
                    conn.SiteMapping_Add(i, ((i - 1) % 10) + 1, "www.testmapping" + i + ".com")
                    );
                var results = conn.ExecuteProc("acms.Site_GetByRootUrl", new ParamCollection().AddInputParam("RootUrl", SqlDbType.VarChar, "www.testmapping4.com"));
                Assert.AreEqual(1, results.Count);
                Assert.AreEqual(4, results.First()["Id"]);
            }
        }

        [TestMethod]
        public void PutInsertTest()
        {
            using (var conn = TestConnection.Begin())
            {
                var sqlParams = new ParamCollection().
                        AddInputParam("id", SqlDbType.Int, null)
                        .AddInputParam("name", SqlDbType.VarChar, "test")
                        .AddInputParam("root", SqlDbType.VarChar, "testroot")
                        .AddInputParam("UseTopics", SqlDbType.Bit, true)
                        .AddInputParam("UseMenus", SqlDbType.Bit, false)
                        .AddInputParam("VersionID", SqlDbType.Timestamp, null)
                        .AddOutputParam("IdOut", SqlDbType.Int)
                        .AddOutputParam("VersionIDOut", SqlDbType.Timestamp)
                        .AddReturnParam(SqlDbType.Int);


                conn.ExecuteProc("acms.Site_Put", sqlParams);

                Assert.AreEqual(0, sqlParams.Last().Value);
                Assert.IsNotNull(sqlParams["IdOut"].Value);

                var result = conn.Site_GetAll();
                Assert.AreEqual(1, result.Count);
                Assert.AreEqual(sqlParams["IdOut"].Value, result.First()["Id"]);
                Assert.AreEqual("test", result.First()["Name"]);
                Assert.AreEqual("testroot", result.First()["Root"]);
                Assert.AreEqual(true, result.First()["UseTopics"]);
                Assert.AreEqual(false, result.First()["UseMenus"]);
                CollectionAssert.AreEqual((byte[])sqlParams["VersionIDOut"].Value, (byte[])result.First()["VersionId"]);
            }
        }

        [TestMethod]
        public void PutUpdateTest()
        {
            using(var conn = new TestConnection())
            {
                Enumerable.Range(1,10).ToList().ForEach(i =>
                    conn.Site_Add(i, "Test " + i, "Root " + i, true, false, false)
                );

                var versionID = (byte[])conn.Site_Get(3)["VersionId"];

                var sqlParams = new ParamCollection().
                        AddInputParam("id", SqlDbType.Int, 3)
                        .AddInputParam("name", SqlDbType.VarChar, "updated_name")
                        .AddInputParam("root", SqlDbType.VarChar, "updated_root")
                        .AddInputParam("UseTopics", SqlDbType.Bit, false)
                        .AddInputParam("UseMenus", SqlDbType.Bit, true)
                        .AddInputParam("VersionID", SqlDbType.Timestamp, versionID)
                        .AddOutputParam("IdOut", SqlDbType.Int)
                        .AddOutputParam("VersionIDOut", SqlDbType.Timestamp)
                        .AddReturnParam(SqlDbType.Int);

                conn.ExecuteProc("acms.Site_Put", sqlParams);

                Assert.AreEqual(10, conn.Site_GetAll().Count);

                var results = conn.Site_GetAll();

                for (int i = 1; i <= results.Count; i++)
                {
                    if (i != 3)
                    {
                        Assert.AreEqual(i, results[i - 1]["Id"]);
                        Assert.AreEqual("Test " + i, results[i - 1]["Name"]);
                        Assert.AreEqual("Root " + i, results[i - 1]["Root"]);
                        Assert.AreEqual(true, results[i - 1]["UseTopics"]);
                        Assert.AreEqual(false, results[i - 1]["UseMenus"]);
                    }
                    else
                    {
                        Assert.AreEqual(3, results[i- 1]["Id"]);
                        Assert.AreEqual("updated_name", results[i - 1]["Name"]);
                        Assert.AreEqual("updated_root", results[i - 1]["Root"]);
                        Assert.AreEqual(false, results[i - 1]["UseTopics"]);
                        Assert.AreEqual(true, results[i - 1]["UseMenus"]);
                        CollectionAssert.AreNotEqual(versionID, (byte[])results[i - 1]["VersionId"]);
                    }
                }
            }

        }

        [TestMethod]
        public void UpdateInsertsPostPosition()
        {
            using (var conn = new TestConnection())
            {
                conn.Site_Add(1, "Site", "SiteRoot", false, false, false);
                conn.Template_Add(1, 1, "Template", null, 1, false, false);
                //add in 5 posts and 5 post positions
                Guid curretGuid = Guid.NewGuid();
                Guid parentGuid = Guid.Empty;
                string parentPath = null;
                string parentSequence = "000";
                for(int i = 1 ; i <= 5; i++)
                {
                    conn.Post_Add(i, 1, curretGuid, parentGuid, i == 1 ? "~" : "Post" + i, "Post " + i, 0, 1, null, null, DateTime.Now, null, null, null, false, false, false, false, null, null);
                    conn.PostPosition_Add(Guid.NewGuid(), i, null, parentPath, null, parentSequence);

                    parentGuid = curretGuid;
                    curretGuid = Guid.NewGuid();

                    if (i == 1)
                    {
                        parentPath += "~";
                    }
                    else
                    {
                        parentPath += "/" + "Post" + i;
                    }
                    parentSequence += "_000"; 
                }

                Assert.AreEqual(5, conn.PostPosition_GetAll().Count);

                //Add a new post and check position has been updated
                var sqlParams = new ParamCollection()
                    .AddInputParam("id", SqlDbType.Int, null)
                    .AddInputParam("SiteId", SqlDbType.Int, 1)
                    .AddInputParam("PostGuid", SqlDbType.UniqueIdentifier, Guid.NewGuid())
                    .AddInputParam("ParentGuid", SqlDbType.UniqueIdentifier, parentGuid)
                    .AddInputParam("Name", SqlDbType.VarChar, "Post6")
                    .AddInputParam("DisplayName", SqlDbType.VarChar, "Post 6")
                    .AddInputParam("TemplateId", SqlDbType.Int, 1)
                    .AddInputParam("ThumbnailId", SqlDbType.Int, null)
                    .AddInputParam("Summary", SqlDbType.VarChar, null)
                    .AddInputParam("Sequence", SqlDbType.Int, 0)
                    .AddInputParam("PublishFrom", SqlDbType.DateTime, null)
                    .AddInputParam("PublishTo", SqlDbType.DateTime, null)
                    .AddInputParam("Notes", SqlDbType.NVarChar, null)
                    .AddInputParam("RequiresPublishing", SqlDbType.Bit, false)
                    .AddInputParam("ReadyToPublish", SqlDbType.Bit, false)
                    .AddInputParam("CreatedDateTime", SqlDbType.DateTime, DateTime.Now)
                    .AddInputParam("DeveloperLocked", SqlDbType.Bit, false)
                    .AddInputParam("TitleSummary", SqlDbType.VarChar, null)
                    .AddInputParam("MetaKeywords", SqlDbType.VarChar, null)
                    .AddInputParam("ConcurencyId", SqlDbType.Timestamp, null)
                    .AddOutputParam("IdOut", SqlDbType.Int)
                    .AddOutputParam("SiteNameOut", SqlDbType.VarChar).SetSize(50)
                    .AddOutputParam("ParentPathOut", SqlDbType.VarChar).SetSize(255)
                    .AddOutputParam("TemplateNameOut", SqlDbType.VarChar).SetSize(255)
                    .AddOutputParam("NodeTypeOut", SqlDbType.Int)
                    .AddOutputParam("SequenceOut", SqlDbType.Int)
                    .AddOutputParam("ConcurencyIdOut", SqlDbType.Timestamp)
                    .AddReturnParam(SqlDbType.Int);

                conn.ExecuteProc("acms.Post_Put", sqlParams);

                //should return 0
                Assert.AreEqual(0, sqlParams.GetReturnValue<int>());

                //check now 6 posts and 6 post records
                var posts = conn.Post_GetAll();
                Assert.AreEqual(6, posts.Count());

                Assert.AreEqual(posts.Last()["Id"], sqlParams.GetOutputValue<int>("IdOut"));

                var postPostions = conn.PostPosition_GetAll();
                Assert.AreEqual(6, postPostions.Count());
                Assert.AreEqual(sqlParams.GetOutputValue<int>("IdOut"), postPostions.Last()["PostId"]);
                Assert.AreEqual("000_000_000_000_000_000", postPostions.Last()["ParentSequence"]);
                Assert.AreEqual("~/Post2/Post3/Post4/Post5/", postPostions.Last()["ParentPath"]);
                Assert.AreEqual(null, postPostions.Last()["PublishDate"]);


            }
        }
    }
}
